[iOS] iOS 9からNSURLSessionのNSURLSessionConfigurationの扱い方が変わっている話
はじめに
こんにちは! 加藤潤です。
今日はNSURLSession
で使用するNSURLSessionConfiguration
に関するネタです。
NSURLSessionとは
iOS 7から登場した、それまで使用していたNSURLConnection
に取って代わる通信処理をを担うクラスです。
皆さんhttp(s)
で使用しているのではないでしょうか。
※ ↓NSURLConnection
はiOS 9.0でDeprecatedになり、代わりにNSURLSession
を使うことが推奨されています。
What's New in iOS 9.0
NSURLSessionConfigurationとは
こちらもiOS 7からNSURLSessionと一緒に登場したクラスです。 タイムアウトの設定やキャッシュポリシー、HTTPヘッダの設定などを行うことができます。
NSURLSessionConfiguration
は以下のようにNSURLSession
のイニシャライザーに渡して使用します。
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() let session = NSURLSession(configuration: configuration)
初期化した後もプロパティを通じてNSURLSessionConfigurationにアクセスできるが...
NSURLSession
を初期化した後でも以下のようにNSURLSessionConfiguration
を取得できます。
let config = session.configuration
もちろんパラメータの設定も可能です。
以下はUser-Agent
を設定している例です。
config.HTTPAdditionalHeaders?["User-Agent"] = "hogehoge"
しかし、ここで1つ注意しなくてはいけないことがあります。
User-Agent
を設定する例を示しましたが、実はこの設定はiOS 9から効かなくなりました。
理由はNSURLSessionのクラスリファレンスでconfiguration
プロパティの説明に書かれていました。
NOTE
On iOS 9 and OS X 10.11, NSURLSession objects store a copy of the NSURLSessionConfiguration object passed to their initializers, such that a session’s configuration is immutable after initialization. Any further changes to mutable properties on the configuration object passed to a session’s initializer or the value returned from a session’s configuration property do not affect the behavior of that session.
On previous versions of iOS and OS X, there is a bug in the implementation, whereby NSURLSession objects instead store a reference to configuration objects passed to their initializers. This allows the behavior of a session to be further configured after initialization by modifying the configuration object passed to a session’s initializer or the value returned from a session’s configuration property. You can ensure consistent behavior across different platform versions by explicitly calling copy on configuration objects passed to an NSURLSession initializer or returned from the configuration property.
日本語でざっくり説明すると大体こんな感じでしょうか。
- iOS 9では
NSURLSession
はイニシャライザーで渡されたNSURLSessionConfiguration
のコピーを保持するため、初期化後にconfiguration
プロパティの設定を変更してもNSURLSession
の振る舞いには影響しない。 - iOS 9未満では実装にバグがあり、それによって
NSURLSession
はイニシャライザーで渡されたNSURLSessionConfiguration
の参照を保持する。それによって初期化後にconfiguration
の設定を変更するとNSURLSession
の振る舞いに影響する。
ということで iOS 9からNSURLSession
の初期化後にconfiguration
の設定を変更しても実際の通信には反映されなくなりました。
Alamofireを使った実装例
SwiftのネットワーキングライブラリAlamofireでもNSURLSession
やNSURLSessionConfiguration
は使われているので
上記の挙動の違いに注意して実装する必要があります。
参考までにカスタムのUser-Agentを設定する例を載せておきます。
Alamofireのバージョンは3.3.1
で確認しています。
let configuration = NSURLSessionConfiguration.defaultSessionConfiguration() configuration.HTTPAdditionalHeaders = Manager.defaultHTTPHeaders // カスタムUser-Agentを設定 configuration.HTTPAdditionalHeaders?["User-Agent"] = "hogehoge" let manager = Manager(configuration: configuration)
Manager
を生成する前にconfiguration
の設定を全て行う必要があります。
まとめ
iOS 9がリリースされてからもうだいぶ経ちますが、意外と知らない人もいるのではないかと思い記事にしてみました。
NSURLSessionConfiguration
の設定が反映されなくて困っている人や、iOS 9とそれ未満で挙動が違う問題にハマっている人の助けになれば幸いです。